! Future Vision v4.0d12
! *[ LAP Manager ]*
!
! Written by Joshua M. Thompson
! Copyright (c) 1990-92 Frontier Technologies, Inc.

! Format of a destination list "DEST()":
!
! DEST(0) = Number of destinations in the list.
! DEST(x) = Site ID of destination number X, where 1<=X<=DEST(0).  If the site
!           is nonzero [standard], then automatic routing using the preferred
!           network routes is used to reach that destination.  If, however, the
!           site number is zero, then this destination uses a custom routing
!           path.
!
! DEST(x,0) = Number of sites in custom routing list for destination number
!             X, where 1<=X<=DEST(0).  This value must be at least two for
!             reasons explained below, and cannot exceed 255 (the maximum
!             value for a 2nd array dimension in METAL).
! DEST(x,y) = Destination number Y in the custom routing list number X, where
!             1<=X<=DEST(0) and 2<=Y<=DEST(X,0).  The custom routing list
!             _must_ begin with the source site and end with the final
!             destination, hence the minimum limit of 2 imposed for DEST(X,0).
!
! Site flags is a 32-bit long flags word, defined as follows:
!
!	    bit 0 : Site type (0=P1, 1=P2)
!	bits 1-31 : Reserved; set to zeroes
!
! Format of ROUTES files:
!
! Each record describes the data on how to reach that site from the local site.
! The records are 16 bytes long as and are constructed as follows:
!
!  +0 : Next hop site of default path to this site	2 bytes
!  +2 : Number of hops required to reach this site	2 bytes
!  +4 : Cost of this link in 100ths of a cent		4 bytes
!  +8 : Length of the link in 10ths of a kilometer	4 bytes
! +12 : Speed of link in bytes per second		2 bytes
! +14 : Route flags					2 bytes
!
! Format of MAP files:
!
! The map file describes all connections between sites on the network.  Each
! 256-byte record describes the connections of one site and is divided into
! 16 subrecords of 16 bytes each.  Each subbrecord describes one connection,
! so each site can connect to at most 16 others.  The subrecords are
! constructed as follows:
!
!  +0 : Destination site for this link			2 bytes
!  +2 : Cost of this link in 100ths of a cent		4 bytes
!  +6 : Length of the link in 10ths of a kilometer	4 bytes
! +10 : Speed of link in bytes per second		2 bytes
! +14 : Weight of this link				4 bytes

! LAP Manager Error Codes:
!
! $0201 = Bad LM Call
! $0202 = LM Not Initialized
! $0203 = LM Already Initialized
! $0204 = Protocol table full
! $0205 = Protocol code not found
! $0206 = Invalid protocol number
! $0207 = Illegal operation on internal protocol
! $0208 = Wrong protocol type
! $0209 = Client ID already in use
! $020A = Bad data buffer type
! $020B = Protocol refused net number assignment
! $020C = [reserved]
! $020D = Packet Damaged
! $020E = Invalid site number
! $020F = Destination List Error
! $0210 = Invalid client ID/owner error
! $0211 = Invalid link/route

DispatchLM
 if func>9 gosub IntLM_CheckStarted
 on func goto LM_BootInit,LM_Startup,LM_Shutdown,LM_Status,LM_Version, ->
              ]err,]err,]err,LM_SystemTask, ->
              LM_InstallProt,LM_RemoveProt,LM_GetNumProts, ->
              LM_ReadPacket,LM_WritePacket, LM_CheckBuffer,LM_FreeBuffer, ->
              LM_AddID,LM_DeleteID, ->
              LM_GetAddress,LM_GetNetworkNumber,LM_SetNetworkNumber, ->
              LM_GetLinkInfo,LM_GetProtocolInfo,LM_GetSiteInfo,LM_GetRouteInfo
]err
 err=$0001:return

! Initialize the LAP Manager at system boot time.
!
! Entry conditions:
!
! (None)
!
! Exit conditions:
!
! LAP Manager is initialized.  All drivers present in the "1/L/"
! directory are loaded and installed (but not started) at this time.

LM_BootInit
 pushvar f$,x,y
 clear lap(0) to lap(65535)		! LAP Manager parameters
 clear lapp$(0) to lapp$(65535)		! Protocol filenames
 lap$(0)="1/L/":lap$(1)="4/LAP.CLIENTS"
 gosub SaveFile1
 open #1,lap$(0):input #1,&1$
 while (&1$<>"") and (lap(1)<=256)
    &1$=&1$[2,15]:&1=instring(" ",&1$):if &1 &1$=left$(&1$,&1-1)
    if right$(&1$,2)=".S" gosub ]TryToInstall(&1$)
    input #1,&1$
 end while
 close #1
 long if not filesize(lap$(1))
    create lap$(1),6
    gosub IntLM_WriteIDrec($0100,"~Future_Vision")
    gosub IntLM_WriteIDrec($0101,"~Future_Vision")
 end if
 gosub RestoreFile1
 pullvar y,x,f$
 return
]TryToInstall
 f$=lap$(0)+left$(&1$,len(&1$)-2)
 y=1:prot=lap(1)+1:runsub f$,"Dispatcher":if err return
 lap(1)==+1:lapp$(lap(1))=f$
 err=0:return

! Start up the LAP Manager, if it is not already started.  All installed
! protocols are also started up at this time.
!
! Entry conditions:
!
! (None)
!
! Exit conditions:
!
! LAP Manager and all installed protocols are started up.
!
! Error codes:
!
! LM Already Initialized

LM_Startup
 if lap(0) err=$0203:return
 lap(0)=1:&1=1
 while &1<=lap(1)
    gosub IntLM_CallLAP(&1,2)
    &1==+1
 end while
 return

! Shut down the LAP Manager, provided it is started up.  All installed
! protocols are shut down (but _not removed_) at this time.
!
! Entry conditions:
!
! (None)
!
! Exit conditions:
!
! LAP Manager and all installed protocols are shut down.
!
! Error codes:
!
! LM Not Initialized

LM_Shutdown
 gosub IntLM_CheckStarted
 &1=1
 while &1<=lap(1)
    gosub IntLM_CallLAP(&1,3)
    &1==+1
 end while
 lap(0)=0:return

! Return the status of the LAP Manager.
!
! Entry conditions:
!
! (None)
!
! Exit conditions:
!
! STATUS = Status, nonzero indicates started up and zero indicates shut down.
!
! Error codes:
!
! (None)

LM_Status
 status=lap(0):return

! Return the version number of the LAP Manager.
!
! Entry conditions:
!
! (None)
!
! Exit conditions:
!
! VERS = Version number in standard FV tool form.
!
! Error codes:
!
! (None)

LM_Version
 vers=$8100:return

! Allow the specified protocol to perform system tasks
!
! Entry conditions:
!
! PROT = Protocol number
!
! Exit conditions:
!
! (None)
!
! Error codes:
!
! LM Not Initialized
! Invalid Protocol Number

LM_SystemTask
 gosub IntLM_CheckStarted
 gosub IntLM_CallLAP(prot,9)
 return

! Install a new external LAP protocol into the list of available protocols.
!
! Entry conditions:
!
! F$ = Filename of code file for the new LAP
!
! Exit conditions:
!
! PROT = Protocol number for new protocol or 0 if error.
!
! Error codes:
!
! LM Not Initialized
! General External LAP Error
! Protocol Table Full
! Protocol code file not found

LM_InstallProt
 prot=0
 if fileinfo$(f$+".S")="" err=$0205:return
 if lap(1)=256 err=$0204:return
 pushvar x,y,net
 prot=lap(1)+1
 y=10:runsub f$,"Dispatcher":if err goto ]exit
 y=1:runsub f$,"Dispatcher":if err goto ]exit
 y=2:runsub f$,"Dispatcher":if err goto ]exit
 lap(1)==+1:lapp$(lap(1))=f$
]exit
 pullvar net,y,x:return

! Remove a specified external protocol from the protocol list
!
! Entry conditions:
!
! PROT = Protocol number to remove
!
! Exit conditions:
!
! Protocol shut down and removed if possible
!
! Error codes:
!
! LM Not Initialized
! Illegal Operation on Internal Protocol
! Invalid Protocol Number

LM_RemoveProt
 gosub IntLM_CheckProtNum
 gosub IntLM_CallLAP(prot,3)
 gosub IntLM_CallLAP(prot,11)
 if prot=lap(1) goto ]done
 for &1=prot to lap(1)-1
    lapp$(&1)=lapp$(&1+1)
 next
]done
 lapp$(lap(1))="":lap(1)==-1
 free:return

! Return the number of protocols installed
!
! Entry conditions:
!
! (None)
!
! Exit conditions:
!
! NUMP = Number of protocols installed.
!
! Error codes:
!
! LM Not Initialized

LM_GetNumProts
 gosub ParmLM_GetNumProts()(nump)
 return

! Search for and/or read LAP data packets the network.
!
! Entry conditions:
!
!   PROT = Protocol Number
!  BUFF$ = Name of buffer file which will hold the packet data.
!  FLAGS = Search Flags.  This is a bitmapped value as follows:
!
!		bit 0 : Read Flag.  If this is clear, the packet information
!			is returned but not the packet data.  This is useful
!			for determining if the next packet is actually wanted.
!			Set this bit for normal reads.
!		bit 1 : Delete Flag.  Set this bit to instruct the protocol to
!			purge the packet after it is read.  Leaving this bit
!			clear will cause the packet to be left as unread; this
!			is useful for writing network data "spy" programs.
!		bit 2 : Ignored Deleted Packets.  Clearing this bit will return
!			a packet even if has been marked as deleted.  This bit
!			allows network utilities to examine all packets in a
!			spool file, even deleted ones.
!		bit 3 : Check Client ID.  If this bit is set, only packets
!			with the specified ID will be returned.
!		bits 4-15 : Reserved; set to zero for future compatibility.
!   CLID = Client ID.  When bit 3 is set in the flag word, only packets with
!	   this client ID will be returned.
!   BPOS = Buffer position.  This value specified the packet in the buffer
!	   at which the search should begin.  Packet numbering starts at one.
! DTYP() = Specifies which buffer file should be searched.  DTYP(1) is the site
!	   number and DTYP(0) is 0 for that site's incoming buffer file or 1
!	   for its outgoing buffer file.
!
! Exit conditions:
!
!   CLID = The two-byte client ID number for this packet.
!    SRC = ID number of the site that sent this packet.
!  FLAGS = Packet Flags for protocols which support them.
! DEST() = The destination list of this packet.
!  BUFF$ = The data buffer will hold the packet data, if it was requested.
!   SIZE = Size of packet data (even if the data was not returned).  Will be
!          zero if there was an error.
!   BPOS = On exit this will point to the packet immediately following the one
!	   just read, so by setting it to zero and making a set of calls you
!	   can read consecutive packets without the protocol having to search
!	   from the beginning of the buffer file for an unread packet.
!
! Error codes:
!
! LM Not Initialized
! Invalid protocol number
! Bad data buffer type
! Data buffer too small
! Packet damaged

LM_ReadPacket
 gosub IntLM_CheckProtNum
 gosub IntLM_CallLAP(prot,13)
 return

! Write a packet of data to the network.
!
! Entry conditions:
!
!   PROT = Protocol Number
!    SRC = Source site ID to attach to this packet or zero for the local ID.
!  FLAGS = Packet Flags, for protocols that support them.
!   CLID = The two-byte client ID number for this packet.
! DEST() = Destination list.
!  BUFF$ = Buffer file holding data to write.
! DTYP() = Specifies which buffer file should receive the packet.  DTYP(1) is
!	   the site number and DTYP(0) is 0 for that site's incoming buffer
!	   file or 1 for its outgoing buffer file.  However, if you specify
!	   1/0 as the destination ("site #0 outgoing"), then the packet is
!          routed to all necessary output files based on the destination list.
!
! Exit conditions:
!
! Packet is written to the network.
!
! Error codes:
!
! LM Not Initialized
! Invalid protocol number
! Bad data buffer type

LM_WritePacket
 gosub IntLM_CheckProtNum
 gosub IntLM_CallLAP(prot,14)
 return

! Returns information about the packets currently in the input buffer.
!
! Entry conditions:
!
!  PROT = Protocol number.
!  FLAGS = Search Flags.  This is a bitmapped value as follows:
!
!		bit 0 : Read Flag.  [ignored]
!		bit 1 : Delete Flag.  Set this bit to instruct the protocol to
!			purge packets after they are counted.  By setting this
!			bit, a program can filter packets of a specified type.
!		bit 2 : Ignored Deleted Packets.  Clearing this bit will count
!			a packet even if has been marked as deleted.  This bit
!			allows network utilities to examine all packets in a
!			spool file, even deleted ones.
!		bit 3 : Check Client ID.  If this bit is set, only packets
!			with the specified ID will be counted.
!		bits 4-15 : Reserved; set to zero for future compatibility.
!   CLID = Client ID.  When bit 3 is set in the flag word, only packets with
!	   this client ID will be counted.
!   BPOS = Buffer position.  This value specified the packet in the buffer
!	   at which the search should begin.  Packet numbering starts at one.
! DTYP() = Specifies which buffer file should be searched.  DTYP(1) is the site
!	   number and DTYP(0) is 0 for that site's incoming buffer file or 1
!	   for its outgoing buffer file.
!
! Exit conditions:
!
! NUMP = Number of packets in the input buffer.
!
! Error codes:
!
! LM Not Initialized
! Invalid protocol number

LM_CheckBuffer
 gosub IntLM_CheckProtNum
 gosub IntLM_CallLAP(prot,15)
 return

! Frees the input buffer of all deleted/already read packets..
!
! Entry conditions:
!
!  PROT = Protocol number.
! DTYP() = Specifies which buffer file should be purged.  DTYP(1) is the site
!	   number and DTYP(0) is 0 for that site's incoming buffer file or 1
!	   for its outgoing buffer file.
!
! Exit conditions:
!
! All deleted packets are purged from the specified buffer.
!
! Error codes:
!
! LM Not Initialized
! Invalid protocol number

LM_FreeBuffer
 gosub IntLM_CheckProtNum
 gosub IntLM_CallLAP(prot,16)
 return

! Add the specified client ID to the LM's list of valid IDs.
!
! Entry conditions:
!
! CLID = Client ID to allocate
!
! Exit conditions:
!
! ID is allocated using current Network Manager application name.  Only the
! same application (or the system SuperUser program) can delete this ID later.
!
! Error codes:
!
! LM Not Initialized
! Client ID already in use

LM_AddID
 gosub IntLM_ReadIDrec(clid)(&1$)
 if &1$<>"" err=$0209:return
 gosub ParmNET_GetCurrApp()(&1,&1$)
 gosub IntLM_WriteIDrec(clid,&1$)
 return

! Remove the specified client ID from the LM's list of valid IDs.
!
! Entry conditions:
!
! CLID = Client ID to remove
!
! Exit conditions:
!
! Client ID is deallocated.
!
! Error codes:
!
! LM Not Initialized
! Invalid client ID/owner error

LM_DeleteID
 gosub IntLM_CheckIDowner(clid)
 gosub IntLM_WipeIDrec(clid)
 return

! Return the protocol address for a given site using a given protocol.
!
! Entry conditions:
!
! PROT = LAP protocol number
! SITE = Site number
!
! Exit conditions:
!
! A$ = Protocol address or null string if error.  This value is returned
!      as a string to allow for possible long addresses.
!
! Error codes:
!
! LM Not Initialized
! Invalid protocol number
! Invalid site number

LM_GetAddress
 gosub IntLM_CheckProtNum
 gosub IntLM_CallLAP(prot,19)
 return

! Return the network number parameter associated with a given protocol.
!
! Entry conditions:
!
! PROT = Protocol Number
!
! Exit conditions:
!
! NET = Network number
!
! Error codes:
!
! LM not initialized
! Invalid protocol number

LM_GetNetworkNumber
 gosub IntLM_ChecKProtNum
 gosub IntLM_CallLAP(prot,20)
 return

! Set the network number parameter associated with a given protocol.
!
! Entry conditions:
!
! PROT = Protocol Number
!  NET = Network number to assign to the protocol.
!
! Exit conditions:
!
! New protocol number is assigned.
!
! Error Codes:
!
! LM Not Initialized
! Invalid protocol number.
! Invalid network number (assignment refused by the driver itself)

LM_SetNetworkNumber
 gosub IntLM_CheckProtNum
 gosub IntLM_CallLAP(prot,21)
 return

! Returns information (speed, length, cost, etc) about a given link to a given
! site.
!
! Entry conditions:
!
! PROT = Protocol number
!  SRC = Source site number for the link
!  DST = Destination site number for the link
!
! Exit conditions:
!
! (for all returned values, a 0 means "unknown" or "not applicable")
!
!   HOPS = Total number of hops in this route
!    HOP = Next hop site to get from the source to the destination.  This is
!	   only useful if SRC=<local id>, otherwise, HOP=DST since each site
!	   only knows its own part of the routing table.
!  SPEED = Speed of this link in bytes per second
! LENGTH = Length of the link in tenths of a kilometer
!   COST = Cost of this link in hundredths of a cent per kilobyte.
!
! Error codes:
!
! LM Not Initialized
! Invalid protocol number
! Invalid link/route

LM_GetLinkInfo
 gosub IntLM_CheckProtNum
 gosub IntLM_CallLAP(prot,22)
 return

! Return detailed information about a given link-level protocol.
!
! Entry conditions:
!
! PROT = LAP Protocol Number
!
! Exit conditions:
!
!   N1$ = Full protocol name
!   N2$ = Abbreviated name
!   NET = Network number associated with this protocol.  This value is used by
!	  FDP and is not used at all by the LAP drivers.
!  SITE = Local site ID on this protocol's network.
! FLAGS = Protocol flags.  This is a bitmapped value:
!
!		bit 0 : External protocol flag (0=No, 1=Yes)
!		bits 1-23 : [reserved, set to 0 for future compatibility]
!
! Error codes:
!
! LM Not Initialized
! Invalid Protocol Number

LM_GetProtocolInfo
 gosub IntLM_CheckProtNum
 gosub IntLM_CallLAP(prot,23)
 return

! Return complete information about a given site ID.
!
! Entry conditions:
!
! PROT = Protocol number
! SITE = Site ID number
!
! Exit conditions:
!
!    A$ = Site's protocol address
! FLAGS = Site flags.
!  BAUD = Site's maximum baud rate, for sites connected via modems.
!  BSNT = Total number of bytes sent to this site.
!  BRCV = Total number of bytes received from this site.
!   LC$ = Date/time of last connection to this site.
!   P1$ = Site's call-in password, for protocols requiring passwords.
!   P2$ = Site's call-out passoword, """"
!
! Error codes:
!
! LM Not Initialized
! Invalid protocol number
! Invalid site number

LM_GetSiteInfo
 gosub IntLM_CheckProtNum
 gosub IntLM_CallLAP(prot,24)
 return

! Similar to LM_GetLinkInfo, but returns the information for a specified ROUTE
! instead of a single link.
!
! Entry conditions:
!
!   PROT = Protocol number
!   DEST = Route number in destination list to return information for.
! DEST() = Standard destination list
!
! Exit conditions:
!
! (for all returned values, a 0 means "unknown" or "not applicable")
!
!   HOPS = Total number of hops in this route
!  SPEED = Speed of this link in bytes per second
! LENGTH = Length of the link in tenths of a kilometer
!   COST = Cost of this link in hundredths of a cent per kilobyte.
!
! Error codes:
!
! LM Not Initialized
! Invalid protocol number
! Invalid link/route

LM_GetRouteInfo
 gosub IntLM_CheckProtNum
 gosub IntLM_CallLAP(prot,25)
 return

! Call protocol driver &1, function &2

IntLM_CallLAP
 pushvar prot,y
 prot=&1:y=&2
 runsub lapp$(&1),"Dispatcher"
 pullvar y,prot
 return

! Check to make sure protocol number in X is a valid LAP protocol number.

IntLM_CheckProtNum
 if (prot<1) or (prot>lap(1)) err=$0206:pop
 return

! Check to make sure that the LAP Manager has been initialized

IntLM_CheckStarted
 if not lap(1) pop:err=$0202
 return

! Return owner of client ID &1 in &1$.  Returns null if channel not allocated

IntLM_ReadIDrec
 gosub SaveFile2
 open #2,lap$(1):position #2,64,&1:input #2,&2$ cr &1$:close #2
 gosub RestoreFile2
 if &2$<>"*-* VaLiD *-*" &1$=""
 return

! Allocate client ID &1 to program &2$

IntLM_WriteIDrec
 gosub SaveFile2
 open #2,lap$(1):position #2,64,&1:? #2,"*-* VaLiD *-*" cr &2$:close #2
 gosub RestoreFile2
 return

! Wipe (clear) client ID &1 to an unowned status.

IntLM_WipeIDrec
 gosub SaveFile2
 open #2,lap$(1):position #2,64,&1:? #2,"*-* WiPeD *-*":close #2
 gosub RestoreFile2
 return

! Check the owner of client ID &1 and make sure it's the current app

IntLM_CheckIDowner
 gosub ParmNET_GetCurrApp()(&2,&2$)
 gosub IntLM_ReadIDrec(&1)(&1$)
 if &1$<>&2$ err=$0210:pop
 return

! Return number of installed protocols in &1

ParmLM_GetNumProts
 &1=lap(1):return
